#include "StdAfx.h"
#include "SmartDate.h"

using namespace Adaptive::Foundation;

/*--------------------------------------------------------------------------------
 * Constructor / Dispose / Destructor Methods
 *------------------------------------------------------------------------------*/
#pragma region Constructor / Dispose / Destructor Methods
static SmartDateTime::SmartDateTime()
{
	_daysToMonth365 = gcnew array<int>(13) { 0, 0x1f, 0x3b, 90, 120, 0x97, 0xb5, 0xd4, 0xf3, 0x111, 0x130, 0x14e, 0x16d };
	_daysToMonth366 = gcnew array<int>(13) { 0, 0x1f, 60, 0x5b, 0x79, 0x98, 0xb6, 0xd5, 0xf4, 0x112, 0x131, 0x14f, 0x16e };
}
SmartDateTime::SmartDateTime(__int64 ticks)
{
	if ((ticks < 0L) || (ticks > 0x2bca2875f4373fffL))
	{
		_isNull = true;
		throw gcnew ArgumentOutOfRangeException("ticks", "Invalid tick count provided.");
	}
    _dateData = (unsigned __int64) ticks;
	_isNull = false;
	_isEmpty = false;
}
SmartDateTime::SmartDateTime(unsigned __int64 dateData)
{
	_dateData = dateData;
	_isNull = false;
	_isEmpty = false;
}
SmartDateTime::SmartDateTime(__int64 ticks, DateTimeKind kind)
{
	if ((ticks < 0L) || (ticks > 0x2bca2875f4373fffL))
	{
		_isNull = true;
		_isEmpty = false;
		throw gcnew ArgumentOutOfRangeException("ticks", "Invalid tick count provided.");
	}

	if ((kind < DateTimeKind::Unspecified) || (kind > DateTimeKind::Local))
	{
		_isNull = true;
		throw gcnew ArgumentException("Invalid DateTimeKind argument.", "kind");
	}
	_dateData = (unsigned __int64) (ticks | (((__int64) kind) << 0x3e));
	_isNull = false;
	_isEmpty = false;
}
SmartDateTime::SmartDateTime(SerializationInfo^ info, StreamingContext context)
{
	SerializationInfoEnumerator^ enumerator = nullptr;		//Serialization enumerator.
	String^			name = nullptr;							//Field name to read.
	bool			ticksFlag = false;						//Ticks field flag.
	bool			dateDataFlag = false;					//Date data field flag.
	__int64			ticksValue = 0;							//Ticks value.
	__int64			internalTicks = 0;						//Internal ticks conversion value.
	unsigned __int64	dateValue = 0;							//Date value.

	if (info == nullptr)
	{
		throw gcnew ArgumentNullException("info");
	}

	enumerator = info->GetEnumerator();
	while (enumerator->MoveNext())
	{
		name = enumerator->Name;
		if (name != nullptr)
		{
			if (name == "ticks")
			{
				ticksValue = Convert::ToInt64(enumerator->Value, CultureInfo::InvariantCulture);
				ticksFlag = true;
			}
			else if (name == "dateData")
			{
				//Name = "date Data"
				dateValue = Convert::ToUInt64(enumerator->Value, CultureInfo::InvariantCulture);
				dateDataFlag = true;
			}
		}
	}

	if (dateDataFlag)
	{
		_dateData = dateValue;
	}
	else
	{
		if (!ticksFlag)
		{
			throw gcnew SerializationException("Missing serialization data.");
		}
		_dateData = (unsigned __int64)ticksFlag;
	}

	internalTicks = this->InternalTicks;
	if ((internalTicks < 0L) || (internalTicks > 0x2bca2875f4373fffL))
	{
		throw gcnew SerializationException("Serialization error: date/time ticks out of range.");
	}
	
}
SmartDateTime::SmartDateTime(int year, int month, int day)
{
	_dateData = (unsigned __int64)DateToTicks(year, month, day);
}
SmartDateTime::SmartDateTime(__int64 ticks, DateTimeKind kind, bool isAmbiguousDst)
{
	unsigned __int64 data = ticks;
	unsigned __int64 left = (unsigned __int64)-4611686018427387904;
	unsigned __int64 right = 9223372036854775808;
	__int64 result = 0;

	if ((ticks < 0L) || (ticks > 0x2bca2875f4373fffL))
	{
		throw gcnew ArgumentOutOfRangeException("ticks", "Invalid tick count provided.");
	}
	result = (__int64)data | (isAmbiguousDst ? left : right);
	_dateData = (unsigned __int64)result;
}
SmartDateTime::SmartDateTime(int year, int month, int day, Calendar^ calendar) 
{
	if (calendar == nullptr)
	{
		throw gcnew ArgumentNullException("calendar");
	}
	_dateData = (unsigned __int64) calendar->ToDateTime(year, month, day, 0, 0, 0, 0).Ticks;
}
SmartDateTime::SmartDateTime(int year, int month, int day, int hour, int minute, int second)
{
	_dateData = (unsigned __int64) (DateToTicks(year, month, day) + TimeToTicks(hour, minute, second));
}
SmartDateTime::SmartDateTime(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
{
	__int64 tickValue = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);

	if ((kind < DateTimeKind::Unspecified) || (kind > DateTimeKind::Local))
	{
		throw gcnew ArgumentException("Invalid date/time kind value provided.", "kind");
	}
	_dateData = (unsigned __int64) (tickValue | (((__int64) kind) << 0x3e));
}
SmartDateTime::SmartDateTime(int year, int month, int day, int hour, int minute, int second, Calendar^ calendar)
{
	if (calendar == nullptr)
	{
		throw gcnew ArgumentNullException("calendar");
	}
	_dateData = (unsigned __int64) calendar->ToDateTime(year, month, day, hour, minute, second, 0).Ticks;
}
SmartDateTime::SmartDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond)
{
	__int64 tickValue = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);

	if ((millisecond < 0) || (millisecond >= 0x3e8))
	{
		throw gcnew ArgumentOutOfRangeException("millisecond", String::Format(CultureInfo::CurrentCulture, "Argument out of range.", 
			gcnew array<int> { 0, 0x3e7 }));
	}
	tickValue += millisecond * 0x2710L;
	if ((tickValue < 0L) || (tickValue > 0x2bca2875f4373fffL))
	{
		throw gcnew ArgumentException("Out of date/time range value.");
	}
	_dateData = (unsigned __int64) tickValue;
}
SmartDateTime::SmartDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind)
{
	__int64 tickValue = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
	array<int>^ params = nullptr;

	if ((millisecond < 0) || (millisecond >= 0x3e8))
	{
		params = gcnew array<int>(2) {0, 0x3e7};

		throw gcnew ArgumentOutOfRangeException("millisecond", String::Format(CultureInfo::CurrentCulture, "ArgumentOutOfRange_Range", 
			params));
	}
	tickValue += millisecond * 0x2710L;
	if ((tickValue < 0L) || (tickValue > 0x2bca2875f4373fffL))
	{
		throw gcnew ArgumentException("Invalid date/time values specified.");
	}
	if ((kind < DateTimeKind::Unspecified) || (kind > DateTimeKind::Local))
	{
		throw gcnew ArgumentException("Invalid DateTimeKind provided.", "kind");
	}
	_dateData = (unsigned __int64) (tickValue | (((__int64) kind) << 0x3e));
}
SmartDateTime::SmartDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar^ calendar)
{
	__int64 ticks  = 0;

	if (calendar == nullptr)
	{
		throw gcnew ArgumentNullException("calendar");
	}
	
	ticks = calendar->ToDateTime(year, month, day, hour, minute, second, 0).Ticks;
	if ((millisecond < 0) || (millisecond >= 0x3e8))
	{
		throw gcnew ArgumentOutOfRangeException("millisecond", String::Format(CultureInfo::CurrentCulture, "ArgumentOutOfRange_Range", 
			gcnew array<int>(2) { 0, 0x3e7 }));
	}
	ticks += millisecond * 0x2710L;
	if ((ticks < 0L) || (ticks > 0x2bca2875f4373fffL))
	{
		throw gcnew ArgumentException("Arg_DateTimeRange");
	}
	_dateData = (unsigned __int64) ticks;
}
SmartDateTime::SmartDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar^ calendar, DateTimeKind kind)
{
	if (calendar == nullptr)
	{
		throw gcnew ArgumentNullException("calendar");
	}
	__int64 ticks = calendar->ToDateTime(year, month, day, hour, minute, second, 0).Ticks;
	if ((millisecond < 0) || (millisecond >= 0x3e8))
	{
		throw gcnew ArgumentOutOfRangeException("millisecond", String::Format(CultureInfo::CurrentCulture, 
			"ArgumentOutOfRange_Range", gcnew array<int> { 0, 0x3e7 }));
	}
	ticks += millisecond * 0x2710L;
	if ((ticks < 0L) || (ticks > 0x2bca2875f4373fffL))
	{
		throw gcnew ArgumentException("Arg_DateTimeRange");
	}
	if ((kind < DateTimeKind::Unspecified) || (kind > DateTimeKind::Local))
	{
		throw gcnew ArgumentException("Argument_InvalidDateTimeKind", "kind");
	}
	
	_dateData = (unsigned __int64) (ticks | (((__int64) kind) << 0x3e));
}
SmartDateTime::SmartDateTime(DateTime originalValue)
{
	_isNull = false;
	_isEmpty = false;
	_dateData = originalValue.Ticks;
}
SmartDateTime::SmartDateTime(bool isNull)
{
	_isNull = isNull;
	_isEmpty = !isNull;
}
SmartDateTime::SmartDateTime(Object^ originalValue)
{
	if ((originalValue == nullptr) || (originalValue == System::DBNull::typeid))
	{
		_isNull = true;
		_isEmpty = false;
		_dateData = 0;
	}
	else
	{
		if (originalValue == DateTime::typeid)
		{
			_dateData = ((DateTime)originalValue).Ticks;
		}
		else if (originalValue == SmartDateTime::typeid)
		{
			_dateData = ((SmartDateTime)originalValue).InternalTicks;
		}
		else
		{
			_isNull = true;
			_isEmpty = false;
			_dateData = 0;
		}			
	}
}
SmartDateTime::SmartDateTime(DateTime originalValue, bool isNull)
{
	if (isNull)
	{
		_isNull = true;
		_isEmpty = false;
		_dateData = 0;
	}
	else
	{
		_isNull = false;
		_isEmpty = false;
		_dateData = ((DateTime)originalValue).Ticks;
	}
}
SmartDateTime::SmartDateTime(bool isNull, bool isEmpty)
{
	if (isNull)
	{
		_isNull = true;
		_isEmpty = false;
	}	
	else if (isEmpty)
	{
		_isNull = false;
		_isEmpty = true;
	}
	else
	{
		_isNull = false;
		_isEmpty = false;
	}
	_dateData = 0;
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Properties
 *------------------------------------------------------------------------------*/
#pragma region Public Properties
SmartDateTime SmartDateTime::Null::get()
{
	return *(gcnew SmartDateTime(true, false));
}
SmartDateTime SmartDateTime::Empty::get()
{
	return *(gcnew SmartDateTime(false, true));
}
SmartDateTime SmartDateTime::MaxValue::get()
{
	return *(gcnew SmartDateTime(0x2bca2875f4373fffL, DateTimeKind::Unspecified));
}
SmartDateTime SmartDateTime::MinValue::get()
{
	return *(gcnew SmartDateTime(0, DateTimeKind::Unspecified));
}
SmartDateTime SmartDateTime::Date::get()
{
	return *(gcnew SmartDateTime(((unsigned __int64) (InternalTicks - (InternalTicks % 0xc92a69c000L))) | this->InternalKind));
}
int SmartDateTime::Day::get()
{
	return GetDatePart(3);
}
DayOfWeek SmartDateTime::XDayOfWeek::get()
{
	return (DayOfWeek) ((int) (((InternalTicks / 0xc92a69c000L) + 1L) % 7L));
}

int SmartDateTime::DayOfYear::get()
{
	return GetDatePart(1);
}
int SmartDateTime::Hour::get()
{
	return (int) ((InternalTicks / 0x861c46800L) % 0x18L);
}
unsigned __int64 SmartDateTime::InternalKind::get()
{
	return (_dateData & 13835058055282163712L);

}
__int64 SmartDateTime::InternalTicks::get()
{
	 return (((__int64) _dateData) & 0x3fffffffffffffffL);
}
DateTimeKind SmartDateTime::Kind::get()
{
	DateTimeKind returnValue = DateTimeKind::Local;

	switch (InternalKind)
   {
        case 0:
			returnValue = DateTimeKind::Unspecified;
			break;

        case 0x4000000000000000L-1:
			returnValue = DateTimeKind::Utc;
			break;
	}
	return returnValue;
}
int SmartDateTime::Millisecond::get()
{
	 return (int) ((InternalTicks / 0x2710L) % 0x3e8L);
}
int SmartDateTime::Minute::get()
{
	  return (int) ((InternalTicks / 0x23c34600L) % 60L);
}
int SmartDateTime::Month::get()
{
	return GetDatePart(2);

}
SmartDateTime SmartDateTime::Now::get()
{
	return UtcNow.ToLocalTime();

}
int SmartDateTime::Second::get()
{
	 return (int) ((InternalTicks / 0x989680L) % 60L);

}
__int64 SmartDateTime::Ticks::get()
{
	return InternalTicks;

}
TimeSpan SmartDateTime::TimeOfDay::get()
{
	return *(gcnew TimeSpan(InternalTicks % 0xc92a69c000L));

}
SmartDateTime SmartDateTime::Today::get()
{
	return Now.Date;

}
SmartDateTime SmartDateTime::UtcNow::get()
{
	return *(gcnew SmartDateTime((unsigned __int64) ((GetSystemTimeAsFileTime() + 0x701ce1722770000L) | 0x4000000000000000L)));

}
int SmartDateTime::Year::get()
{
	return GetDatePart(0);
}
bool SmartDateTime::IsNull::get()
{
	return _isNull;
}
bool SmartDateTime::IsEmpty::get()
{
	return _isEmpty;
}
Object^ SmartDateTime::DBValue::get()
{
	Object^ returnValue = nullptr;

	if (_isNull)
		returnValue = System::DBNull::Value;
	else if (_isEmpty)
		returnValue = DateTime::MinValue;
	else
		returnValue = *(gcnew DateTime(InternalTicks));

	return returnValue;
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Methods / Functions
 *------------------------------------------------------------------------------*/
#pragma region Public Methods / Functions

SmartDateTime SmartDateTime::Add(TimeSpan value)
{
	return AddTicks((__int64)value.Ticks);
}
SmartDateTime SmartDateTime::Add(double value, int scale)
{
	 __int64 num = (__int64) ((value * scale) + ((value >= 0.0) ? 0.5 : -0.5));
    if ((num <= -315537897600000L) || (num >= 0x11efae44cb400L))
    {
        throw gcnew ArgumentOutOfRangeException("value", "ArgumentOutOfRange_AddValue");
    }
    return AddTicks(num * 0x2710L);
}
SmartDateTime SmartDateTime::Add(SmartDateTime value)
{
	return AddTicks(value.Ticks);
}
SmartDateTime SmartDateTime::Add(DateTime value)
{
	return AddTicks(value.Ticks);
}

SmartDateTime SmartDateTime::AddDays(double value)
{
	  return Add(value, 0x5265c00);
}
SmartDateTime SmartDateTime::AddHours(double value)
{
	return Add(value, 0x36ee80);
}
SmartDateTime SmartDateTime::AddMilliseconds(double value) 
{
	return Add(value, 1);
}
SmartDateTime SmartDateTime::AddMinutes(double value)
{
	return Add(value, 0xea60);
}
SmartDateTime SmartDateTime::AddMonths(int value)
{
	if ((value < -120000) || (value > 0x1d4c0))
    {
        throw gcnew ArgumentOutOfRangeException("value", "Invalid number of months specified.");
    }

    int datePart = GetDatePart(0);
    int month = GetDatePart(2);
    int day = GetDatePart(3);
    int num4 = (month - 1) + value;
    if (num4 >= 0)
    {
        month = (num4 % 12) + 1;
        datePart += num4 / 12;
    }
    else
    {
        month = 12 + ((num4 + 1) % 12);
        datePart += (num4 - 11) / 12;
    }
    if ((datePart < 1) || (datePart > 0x270f))
    {
        throw gcnew ArgumentOutOfRangeException("value", "Bate date arithmetic.");
    }
    int num5 = DaysInMonth(datePart, month);
    if (day > num5)
    {
        day = num5;
    }
    return *(gcnew SmartDateTime(((unsigned __int64) (DateToTicks(datePart, month, day) + (InternalTicks % 0xc92a69c000L))) | InternalKind));

}
SmartDateTime SmartDateTime::AddSeconds(double value)
{
	return Add(value, 0x3e8);
}
SmartDateTime SmartDateTime::AddTicks(__int64 value)
{
	__int64 internalTicks = InternalTicks;

    if ((value > (0x2bca2875f4373fffL - internalTicks)) || (value < -internalTicks))
    {
        throw gcnew ArgumentOutOfRangeException("value", "Invalid date arithmetic.");
    }
    return *(gcnew SmartDateTime(((unsigned __int64) (internalTicks + value)) | InternalKind));

}
SmartDateTime SmartDateTime::AddYears(int value) 
{
	if ((value < -10000) || (value > 0x2710))
    {
        throw gcnew ArgumentOutOfRangeException("value", "Invalid number of years specified.");
    }
    return AddMonths(value * 12);
}
int SmartDateTime::CompareTo(Object^ object)
{
	int returnValue = 0;
	DateTime dtTest;
	SmartDateTime stTest;

	if (object == nullptr)
		returnValue = 1;
	else
	{
		if (dynamic_cast<DateTime^>(object) != nullptr)
		{
			dtTest = *(dynamic_cast<DateTime^>(object));
			returnValue = InternalCompare(InternalTicks, dtTest.Ticks);
		}
		else if ( dynamic_cast<SmartDateTime^>(object) != nullptr)
		{
			stTest = *(dynamic_cast<SmartDateTime^>(object));
			returnValue = InternalCompare(InternalTicks, stTest.InternalTicks);
		}
		else
		{
			returnValue = 1;
		}
	}

	return returnValue;
}
int SmartDateTime::Compare(SmartDateTime leftDate, SmartDateTime rightDate)
{
	__int64 leftTicks = leftDate.InternalTicks;
	__int64 rightTicks = rightDate.InternalTicks;
	
	return InternalCompare(leftTicks, rightTicks);
  
}
int SmartDateTime::Compare(Adaptive::Foundation::SmartDateTime leftDate, System::DateTime rightDate) 
{
	__int64 leftTicks = leftDate.InternalTicks;
	__int64 rightTicks = rightDate.Ticks;
	
	return InternalCompare(leftTicks, rightTicks);
}
int SmartDateTime::CompareTo(Adaptive::Foundation::SmartDateTime value) 
{
	return InternalCompare(InternalTicks, value.InternalTicks);
}
int SmartDateTime::CompareTo(System::DateTime value)
{
	return InternalCompare(InternalTicks, value.Ticks);
}
__int64 SmartDateTime::DateToTicks(int year, int month, int day)
{
	array<int>^ numArray = nullptr;

	if (((year >= 1) && (year <= 0x270f)) && ((month >= 1) && (month <= 12)))
    {
        numArray = IsLeapYear(year) ? _daysToMonth366 : _daysToMonth365;
        if ((day >= 1) && (day <= (numArray[month] - numArray[month - 1])))
        {
            int num = year - 1;
            int num2 = ((((((num * 0x16d) + (num / 4)) - (num / 100)) + (num / 400)) + numArray[month - 1]) + day) - 1;
            return (num2 * 0xc92a69c000L);
        }
    }
    throw gcnew ArgumentOutOfRangeException(nullptr, "Bad year, month, or day value.");

}
int SmartDateTime::DaysInMonth(int year, int month)
{
	array<int>^ numArray = nullptr;

	if ((month < 1) || (month > 12))
    {
        throw gcnew ArgumentOutOfRangeException("month", "Invalid month value.");
    }
    numArray = IsLeapYear(year) ? _daysToMonth366 : _daysToMonth365;
    return (numArray[month] - numArray[month - 1]);
}
__int64 SmartDateTime::DoubleDateToTicks(double value)
{
  if ((value >= 2958466.0) || (value <= -657435.0))
    {
        throw gcnew ArgumentException("OLE Date is invalid.");
    }
    __int64 num = (__int64) ((value * 86400000.0) + ((value >= 0.0) ? 0.5 : -0.5));
    if (num < 0L)
    {
        num -= (num % 0x5265c00L) * 2L;
    }
    num += 0x3680b5e1fc00L;
    if ((num < 0L) || (num >= 0x11efae44cb400L))
    {
        throw gcnew ArgumentException("OLE Date error.");
    }
    return (num * 0x2710L);

}
bool SmartDateTime::Equals(Adaptive::Foundation::SmartDateTime leftDate, Adaptive::Foundation::SmartDateTime rightDate)
{
	bool returnValue = false;

	returnValue = (leftDate.IsNull == rightDate.IsNull);
	if (!returnValue)
		returnValue = (leftDate.IsEmpty == rightDate.IsEmpty);
	if (!returnValue)
		returnValue = (leftDate.InternalTicks == rightDate.InternalTicks);

	return returnValue;
}
bool SmartDateTime::Equals(Adaptive::Foundation::SmartDateTime value)
{
	bool returnValue = false;

	returnValue = (_isNull == value.IsNull);
	if (!returnValue)
		returnValue = (_isEmpty == value.IsEmpty);
	if (!returnValue)
		returnValue = (InternalTicks == value.InternalTicks);

	return returnValue;
}
bool SmartDateTime::Equals(System::DateTime value)
{
	bool returnValue = false;

	if ((!_isNull) && (!_isEmpty))
		returnValue = (InternalTicks == value.Ticks);

	return returnValue;
}
bool SmartDateTime::Equals(System::Object ^value)
{
	bool returnValue = false;
	DateTime dtTest;
	SmartDateTime stTest;

	if (value == nullptr)
		returnValue = false;
	else
	{
		if (dynamic_cast<DateTime^>(value) != nullptr)
		{
			dtTest = *(dynamic_cast<DateTime^>(value));
			returnValue = (InternalCompare(InternalTicks, dtTest.Ticks) == 0);
		}
		else if ( dynamic_cast<SmartDateTime^>(value) != nullptr)
		{
			stTest = *(dynamic_cast<SmartDateTime^>(value));
			returnValue = (_isNull == stTest.IsNull);
			if (!returnValue)
				returnValue = (_isEmpty == stTest.IsEmpty);
			if (!returnValue)
				returnValue = (InternalCompare(InternalTicks, stTest.InternalTicks) == 0);
		}
		else
		{
			returnValue = false;
		}
	}

	return returnValue;

}

DateTime SmartDateTime::FromBinary(__int64 dateData)
{
	return DateTime::FromBinary(dateData);
}
DateTime SmartDateTime::FromBinaryRaw(__int64 dateData)
{
	__int64 num = dateData & 0x3fffffffffffffffL;
    if ((num < 0L) || (num > 0x2bca2875f4373fffL))
    {
        throw gcnew ArgumentException("BadBinaryData", "dateData");
    }
    return *(gcnew DateTime((unsigned __int64) dateData));

}
DateTime SmartDateTime::FromFileTime(__int64 fileTime)
{
	return FromFileTimeUtc(fileTime).ToLocalTime();
}
DateTime SmartDateTime::FromFileTimeUtc(__int64 fileTime)
{
	if ((fileTime < 0L) || (fileTime > 0x24c85a5ed1c03fffL))
        throw gcnew ArgumentOutOfRangeException("fileTime", "Invalid file time specified.");
	return *(gcnew DateTime(fileTime + 0x701ce1722770000L, DateTimeKind::Utc));
}
DateTime SmartDateTime::FromOADate(double d)
{
	return *(gcnew DateTime(DoubleDateToTicks(d), DateTimeKind::Unspecified));
}
int SmartDateTime::GetDatePart(int part)
{
	array<int>^ numArray = nullptr;
	int internalTicksInt = (int)(InternalTicks / 0xc92a69c000L);
    int num3 = internalTicksInt / 0x23ab1;
    internalTicksInt -= num3 * 0x23ab1;
    int num4 = internalTicksInt / 0x8eac;
    if (num4 == 4)
    {
        num4 = 3;
    }
    internalTicksInt -= num4 * 0x8eac;
    int num5 = internalTicksInt / 0x5b5;
    internalTicksInt -= num5 * 0x5b5;
    int num6 = internalTicksInt / 0x16d;
    if (num6 == 4)
    {
        num6 = 3;
    }
    if (part == 0)
    {
        return (((((num3 * 400) + (num4 * 100)) + (num5 * 4)) + num6) + 1);
    }
    internalTicksInt -= num6 * 0x16d;
    if (part == 1)
    {
        return (internalTicksInt + 1);
    }
    numArray = ((num6 == 3) && ((num5 != 0x18) || (num4 == 3))) ? _daysToMonth366 : _daysToMonth365;
    int index = internalTicksInt >> 6;
    while (internalTicksInt >= numArray[index])
    {
        index++;
    }
    if (part == 2)
    {
        return index;
    }
    return ((internalTicksInt - numArray[index - 1]) + 1);

}
array<String^>^ SmartDateTime::GetDateTimeFormats()
{
	DateTime dt = *(gcnew DateTime(InternalTicks));
	return dt.GetDateTimeFormats();
}
array<String^>^ SmartDateTime::GetDateTimeFormats(char format)
{
	DateTime dt = *(gcnew DateTime(InternalTicks));
	return dt.GetDateTimeFormats(format);
}
array<String^>^ SmartDateTime::GetDateTimeFormats(IFormatProvider^ provider)
{
	DateTime dt = *(gcnew DateTime(InternalTicks));
	return dt.GetDateTimeFormats(provider);
}
array<String^>^ SmartDateTime::GetDateTimeFormats(char format, IFormatProvider^ provider)
{
	DateTime dt = *(gcnew DateTime(InternalTicks));
	return dt.GetDateTimeFormats(format, provider);
}
int SmartDateTime::GetHashCode()
{
   __int64 internalTicks = InternalTicks;

   return (((int) internalTicks) ^ ((int) (internalTicks >> 0x20)));

}
void SmartDateTime::GetObjectData(SerializationInfo^ info, StreamingContext context)
{
	if (info == nullptr)
	{
		throw gcnew ArgumentNullException("info");
	}

	info->AddValue("ticks", (__int64)InternalTicks);
	info->AddValue("dateData", (unsigned __int64)_dateData);
}
__int64 SmartDateTime::GetSystemTimeAsFileTime()
{
	::FILETIME* ft = new ::FILETIME();
	__int64 returnValue = 0;
	__int64 *data = NULL;

	::GetSystemTimeAsFileTime(ft);
	data = (__int64*)ft;
	returnValue = *data;
	delete(ft);
	return returnValue;
}
System::TypeCode SmartDateTime::GetTypeCode()
{
	if (_isNull)
		return TypeCode::DBNull;
	else
		return TypeCode::DateTime;
}

bool SmartDateTime::IsAmbiguousDaylightSavingTime()
{
	return (InternalKind == 13835058055282163712L);
}
bool SmartDateTime::IsDaylightSavingTime()
{
	DateTime dtValue = *(gcnew DateTime(InternalTicks));

	return TimeZone::CurrentTimeZone->IsDaylightSavingTime(dtValue);
}
bool SmartDateTime::IsLeapYear(int year)
{
	if ((year < 1) || (year > 0x270f))
    {
        throw gcnew ArgumentOutOfRangeException("year", "Bad year specified.");
    }
    if ((year % 4) != 0)
    {
        return false;
    }
    if ((year % 100) == 0)
    {
        return ((year % 400) == 0);
    }
    return true;
}

bool SmartDateTime::operator !=(Adaptive::Foundation::SmartDateTime d1, Adaptive::Foundation::SmartDateTime d2)
{
	return !(d1.Equals(d2));
}
SmartDateTime SmartDateTime::operator +(Adaptive::Foundation::SmartDateTime d, System::TimeSpan t)
{
	__int64 internalTicks = d.InternalTicks;
    __int64 newTicks = t.Ticks;

    if ((newTicks > (0x2bca2875f4373fffL - internalTicks)) || (newTicks < -internalTicks))
    {
        throw gcnew ArgumentOutOfRangeException("t", "Overflow_DateArithmetic");
    }
    return *(gcnew SmartDateTime(((unsigned __int64) (internalTicks + newTicks)) | d.InternalKind));
}
TimeSpan SmartDateTime::operator -(Adaptive::Foundation::SmartDateTime d, Adaptive::Foundation::SmartDateTime t)
{
	return *(gcnew TimeSpan(d.InternalTicks - t.InternalTicks));
}
TimeSpan SmartDateTime::operator -(Adaptive::Foundation::SmartDateTime d1, System::DateTime d2)
{
	return *(gcnew TimeSpan(d1.InternalTicks - d2.Ticks));
}
TimeSpan SmartDateTime::operator -(Adaptive::Foundation::SmartDateTime d1, System::TimeSpan d2)
{
	return *(gcnew TimeSpan(d1.InternalTicks - d2.Ticks));
}
bool SmartDateTime::operator <(Adaptive::Foundation::SmartDateTime t1, Adaptive::Foundation::SmartDateTime t2)
{
	bool returnValue = false;

	if (!t1.Equals(t2))
	{
		if ((t1.IsNull) || (t1.IsEmpty))
			returnValue = true;
		else if ((t2.IsNull) || (t2.IsEmpty))
			returnValue = false;
		else
			returnValue = (t1.InternalTicks < t2.InternalTicks);
	}
	return returnValue;
}
bool SmartDateTime::operator <(Adaptive::Foundation::SmartDateTime d1, System::DateTime d2)
{
	if ((d1.IsEmpty) || (d1.IsNull))
		return true;
	else
		return (d1.InternalTicks < d2.Ticks);
}
bool SmartDateTime::operator <=(Adaptive::Foundation::SmartDateTime t1, Adaptive::Foundation::SmartDateTime t2)
{
	bool returnValue = false;

	returnValue = t1.Equals(t2);
	if (!returnValue)
	{
		if ((t1.IsNull) || (t1.IsEmpty))
			returnValue = true;
		else if ((t2.IsNull) || (t2.IsEmpty))
			returnValue = false;
		else
			returnValue = (t1.InternalTicks < t2.InternalTicks);
	}
	return returnValue;

}
bool SmartDateTime::operator ==(Adaptive::Foundation::SmartDateTime d1, Adaptive::Foundation::SmartDateTime d2)
{
	return d1.Equals(d2);
}
bool SmartDateTime::operator >(Adaptive::Foundation::SmartDateTime t1, Adaptive::Foundation::SmartDateTime t2)
{
	bool returnValue = false;

	if (!t1.Equals(t2))
	{
		if ((t1.IsNull) || (t1.IsEmpty))
			returnValue = false;
		else if ((t2.IsNull) || (t2.IsEmpty))
			returnValue = true;
		else
			returnValue = (t1.InternalTicks > t2.InternalTicks);
	}
	return returnValue;
}
bool SmartDateTime::operator >=(Adaptive::Foundation::SmartDateTime t1, Adaptive::Foundation::SmartDateTime t2)
{
	bool returnValue = false;

	returnValue = (!t1.Equals(t2));
	if (!returnValue)
	{
		if ((t1.IsNull) || (t1.IsEmpty))
			returnValue = false;
		else if ((t2.IsNull) || (t2.IsEmpty))
			returnValue = true;
		else
			returnValue = (t1.InternalTicks > t2.InternalTicks);
	}
	return returnValue;
}
SmartDateTime SmartDateTime::Parse(System::String ^s)
{
	SmartDateTime returnValue;

	if (s == nullptr)
		returnValue = *(gcnew SmartDateTime(true));
	else if (s->Length == 0)
		returnValue = *(gcnew SmartDateTime(false));
	else
	{
		returnValue = *(gcnew SmartDateTime(DateTime::Parse(s)) );
	}
	return returnValue;

}
SmartDateTime SmartDateTime::Parse(System::String ^s, System::IFormatProvider ^provider)
{
	SmartDateTime returnValue;

	if (s == nullptr)
		returnValue = *(gcnew SmartDateTime(true));
	else if (s->Length == 0)
		returnValue = *(gcnew SmartDateTime(false));
	else
	{
		returnValue = *(gcnew SmartDateTime(DateTime::Parse(s, provider)) );
	}
	return returnValue;
}
SmartDateTime SmartDateTime::Parse(System::String ^s, System::IFormatProvider ^provider, System::Globalization::DateTimeStyles styles)
{
	SmartDateTime returnValue;

	if (s == nullptr)
		returnValue = *(gcnew SmartDateTime(true));
	else if (s->Length == 0)
		returnValue = *(gcnew SmartDateTime(false));
	else
	{
		returnValue = *(gcnew SmartDateTime(DateTime::Parse(s, provider, styles)) );
	}
	return returnValue;
}
SmartDateTime SmartDateTime::ParseExact(System::String ^s, cli::array<System::String ^,1> ^formats, System::IFormatProvider ^provider, System::Globalization::DateTimeStyles style)
{
	SmartDateTime returnValue;

	if (s == nullptr)
		returnValue = *(gcnew SmartDateTime(true));
	else if (s->Length == 0)
		returnValue = *(gcnew SmartDateTime(false));
	else
	{
		returnValue = *(gcnew SmartDateTime(DateTime::ParseExact(s, formats, provider, style)));
	}
	return returnValue;
}
SmartDateTime SmartDateTime::ParseExact(System::String ^s, System::String ^format, System::IFormatProvider ^provider)
{
	SmartDateTime returnValue;

	if (s == nullptr)
		returnValue = *(gcnew SmartDateTime(true));
	else if (s->Length == 0)
		returnValue = *(gcnew SmartDateTime(false));
	else
	{
		returnValue = *(gcnew SmartDateTime(DateTime::ParseExact(s, format, provider, DateTimeStyles::None)));
	}
	return returnValue;
}
SmartDateTime SmartDateTime::ParseExact(System::String ^s, System::String ^format, System::IFormatProvider ^provider, System::Globalization::DateTimeStyles style)
{
	SmartDateTime returnValue;

	if (s == nullptr)
		returnValue = *(gcnew SmartDateTime(true));
	else if (s->Length == 0)
		returnValue = *(gcnew SmartDateTime(false));
	else
	{
		returnValue = *(gcnew SmartDateTime(DateTime::ParseExact(s, format, provider, style)));
	}
	return returnValue;
}
SmartDateTime SmartDateTime::SpecifyKind(System::DateTime value, System::DateTimeKind kind)
{
	return *(gcnew SmartDateTime(value.Ticks, kind));
}
TimeSpan SmartDateTime::Subtract(Adaptive::Foundation::SmartDateTime value)
{
	return *(gcnew TimeSpan(InternalTicks - value.InternalTicks));
}
SmartDateTime SmartDateTime::Subtract(System::TimeSpan value)
{
	__int64 internalTicks = InternalTicks;
    __int64 num2 = value.Ticks;

    if ((internalTicks < num2) || ((internalTicks - 0x2bca2875f4373fffL) > num2))
    {
        throw gcnew ArgumentOutOfRangeException("value", "ArgumentOutOfRange_DateArithmetic");
    }
    return *(gcnew SmartDateTime(((unsigned __int64) (internalTicks - num2)) | InternalKind));
}
double SmartDateTime::TicksToOADate(__int64 value)
{
 if (value == 0L)
    {
        return 0.0;
    }
    if (value < 0xc92a69c000L)
    {
        value += 0x85103c0cb83c000L;
    }
    if (value < 0x6efdddaec64000L)
    {
        throw gcnew OverflowException("Arg_OleAutDateInvalid");
    }
    __int64 num = (value - 0x85103c0cb83c000L) / 0x2710L;
    if (num < 0L)
    {
        __int64 num2 = num % 0x5265c00L;
        if (num2 != 0L)
        {
            num -= (0x5265c00L + num2) * 2L;
        }
    }
    return (((double) num) / 86400000.0);

}
__int64 SmartDateTime::TimeToTicks(int hour, int minute, int second)
{ 
	if ((((hour < 0) || (hour >= 0x18)) || ((minute < 0) || (minute >= 60))) || ((second < 0) || (second >= 60)))
    {
        throw gcnew ArgumentOutOfRangeException(nullptr, "Invalid hour, minute, or second(s) value provided.");
    }

	__int64 num = ((hour * 0xe10L) + (minute * 60L)) + second;
    if ((num > 0xd6bf94d5e5L) || (num < -922337203685L))
    {
		throw gcnew ArgumentOutOfRangeException(nullptr, "Overflow in calculation: Time span too __int64.");
    }
    return (num * 0x989680L);
}
__int64 SmartDateTime::ToBinary()
{
	__int64 returnValue = 0;

	if ((!_isNull) && (!_isEmpty))
	{
		if (Kind != DateTimeKind::Local)
		{
			returnValue = (__int64)_dateData;
		}
		else
		{
			DateTime dtValue = *(gcnew DateTime(InternalTicks));
			TimeSpan utcOffset = TimeZone::CurrentTimeZone->GetUtcOffset(dtValue);
			__int64 num2 = Ticks - utcOffset.Ticks;
			if (num2 < 0L)
			{
			num2 = 0x4000000000000000L + num2;
			}
			returnValue = (num2 | 9223372036854775808L);
		}
	}
	return returnValue;
}
__int64 SmartDateTime::ToBinaryRaw()
{
	if ((_isNull) || (_isEmpty))
		return 0;
	else
		return (__int64)_dateData;
}
bool SmartDateTime::ToBoolean(System::IFormatProvider ^provider)
{
	throw gcnew InvalidCastException(String::Format(provider,  
		"Invalid cast from a date/time to boolean!", gcnew array<Object^>(2) {"SmartDateTime", "Boolean"} ));
	return false;
}
unsigned char SmartDateTime::ToByte(System::IFormatProvider ^provider)
{
	throw gcnew InvalidCastException(String::Format(provider, 
		"Invalid cast from a date/time to byte!", gcnew array<Object^>(2) {"SmartDateTime", "Byte"} ));
	return 0;
}
wchar_t SmartDateTime::ToChar(System::IFormatProvider ^provider)
{
	throw gcnew InvalidCastException(String::Format(provider, 
		"Invalid cast from a date/time to character!", gcnew array<Object^>(2) {"SmartDateTime", "Char"} ));
	return 0;
}
DateTime SmartDateTime::ToDateTime(System::IFormatProvider ^provider)
{
	return *(gcnew DateTime(InternalTicks));
}
Decimal SmartDateTime::ToDecimal(System::IFormatProvider ^provider)
{
	throw gcnew InvalidCastException(String::Format(provider, 
		"Invalid cast from a date/time to decimal!", gcnew array<Object^>(2) {"SmartDateTime", "Decimal"} ));
	return 0;
}
double SmartDateTime::ToDouble(System::IFormatProvider^ provider)
{
	throw gcnew InvalidCastException(String::Format(provider, 
		"Invalid cast from a date/time to double!", gcnew array<Object^>(2) {"SmartDateTime", "Double"} ));
	return 0;
}
__int64 SmartDateTime::ToFileTime()
{
	 return ToUniversalTime().ToFileTimeUtc();
}
__int64 SmartDateTime::ToFileTimeUtc()
{
	DateTime dtValue = *(gcnew DateTime(InternalTicks));
	return dtValue.ToFileTimeUtc();
}
short SmartDateTime::ToInt16(System::IFormatProvider ^provider)
{
	throw gcnew InvalidCastException(String::Format(provider, 
		"Invalid cast from a date/time to short integer!", gcnew array<Object^>(2) {"SmartDateTime", "Int16"} ));
	return 0;
}
int SmartDateTime::ToInt32(System::IFormatProvider ^provider)
{
	throw gcnew InvalidCastException(String::Format(provider, 
		"Invalid cast from a date/time to integer!", gcnew array<Object^>(2) {"SmartDateTime", "Int32"} ));
	return 0;
}
__int64 SmartDateTime::ToInt64(IFormatProvider^ provider)
{
	throw gcnew InvalidCastException(String::Format(provider, 
		"Invalid cast from a date/time to __int64 integer!", gcnew array<Object^>(2) {"SmartDateTime", "Int64"} ));
	return 0;
}
SmartDateTime SmartDateTime::ToLocalTime()
{
	DateTime value;
	SmartDateTime returnValue;

	value = TimeZone::CurrentTimeZone->ToLocalTime(*(gcnew DateTime(InternalTicks)));
	returnValue = *(gcnew SmartDateTime((__int64)value.Ticks));
	return returnValue;
}
String^ SmartDateTime::ToLongDateString()
{
	DateTime dtValue = *(gcnew DateTime(InternalTicks));
	return dtValue.ToLongDateString();
}
String^ SmartDateTime::ToLongTimeString()
{
	DateTime dtValue = *(gcnew DateTime(InternalTicks));
	return dtValue.ToLongTimeString();
}
double SmartDateTime::ToOADate()
{
	DateTime dtValue = *(gcnew DateTime(InternalTicks));
	return dtValue.ToOADate();
}
signed char SmartDateTime::ToSByte(System::IFormatProvider ^provider)
{
	throw gcnew InvalidCastException(String::Format(provider, 
		"Invalid cast from a date/time to signed byte!", gcnew array<Object^>(2) {"SmartDateTime", "SByte"} ));
	return 0;
}
String^ SmartDateTime::ToShortDateString()
{
	DateTime dtValue = *(gcnew DateTime(InternalTicks));
	return dtValue.ToShortDateString();
}
String^ SmartDateTime::ToShortTimeString()
{
	DateTime dtValue = *(gcnew DateTime(InternalTicks));
	return dtValue.ToShortTimeString();
}
float SmartDateTime::ToSingle(System::IFormatProvider ^provider)
{
	throw gcnew InvalidCastException(String::Format(provider, 
		"Invalid cast from a date/time to single!", gcnew array<Object^>(2) {"SmartDateTime", "Single"} ));
	return 0;
}
String^ SmartDateTime::ToString()
{
	DateTime dtValue = *(gcnew DateTime(InternalTicks));
	return dtValue.ToString();
}
String^ SmartDateTime::ToString(IFormatProvider^ provider)
{
	DateTime dtValue = *(gcnew DateTime(InternalTicks));
	return dtValue.ToString(provider);
}
String^ SmartDateTime::ToString(String^ format)
{
	DateTime dtValue = *(gcnew DateTime(InternalTicks));
	return dtValue.ToString(format);
}
String^ SmartDateTime::ToString(String^ format, IFormatProvider^ provider)
{
	DateTime dtValue = *(gcnew DateTime(InternalTicks));
	return dtValue.ToString(format, provider);
}

Object^ SmartDateTime::ToType (Type^ type, IFormatProvider^ provider)
{
	Object^ returnBox = nullptr;

	if ((type != System::DateTime::typeid) && (type != SmartDateTime::typeid) && (type != System::String::typeid))
	{
		throw gcnew InvalidCastException(String::Format(CultureInfo::CurrentCulture, 
			"Invalid cast specified.", gcnew array<Object^>(2) {"SmartDateTime", type->Name} ));
	}
	else if (type == DateTime::typeid)
	{
		returnBox = ToDateTime(provider);
	}
	else if (type == SmartDateTime::typeid)
	{
		returnBox = gcnew SmartDateTime(InternalTicks);
	}
	else if (type == String::typeid)
	{
		returnBox = ToString();
	}
	return returnBox;
}
unsigned short SmartDateTime::ToUInt16(System::IFormatProvider ^provider)
{
	throw gcnew InvalidCastException(String::Format(provider, 
		"Invalid cast from a date/time to an unsigned short integer!", gcnew array<Object^>(2) {"SmartDateTime", "UInt16"} ));
	return 0;
}
unsigned int SmartDateTime::ToUInt32(System::IFormatProvider ^provider)
{
	throw gcnew InvalidCastException(String::Format(provider, 
		"Invalid cast from a date/time to an unsigned integer!", gcnew array<Object^>(2) {"SmartDateTime", "UInt32"} ));
	return 0;
}
unsigned __int64 SmartDateTime::ToUInt64(System::IFormatProvider ^provider)
{
	return (unsigned __int64)InternalTicks;
}
DateTime SmartDateTime::ToUniversalTime()
{
	DateTime value = *(gcnew DateTime(InternalTicks));
	return TimeZone::CurrentTimeZone->ToUniversalTime(value);
}

bool SmartDateTime::TryCreate(int year, int month, int day, int hour, int minute, int second, int millisecond, Adaptive::Foundation::SmartDateTime ^result)
{
	array<int>^ numArray = nullptr;

	result = MinValue;
    if (((year < 1) || (year > 0x270f)) || ((month < 1) || (month > 12)))
    {
        return false;
    }
    numArray = IsLeapYear(year) ? _daysToMonth366 : _daysToMonth365;
    if ((day < 1) || (day > (numArray[month] - numArray[month - 1])))
    {
        return false;
    }
    if ((((hour < 0) || (hour >= 0x18)) || ((minute < 0) || (minute >= 60))) || ((second < 0) || (second >= 60)))
    {
        return false;
    }
    if ((millisecond < 0) || (millisecond >= 0x3e8))
    {
        return false;
    }
    __int64 ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
    ticks += millisecond * 0x2710L;
    if ((ticks < 0L) || (ticks > 0x2bca2875f4373fffL))
    {
        return false;
    }
	result = gcnew SmartDateTime(ticks, DateTimeKind::Unspecified);
    return true;

}
bool SmartDateTime::TryParse(System::String ^s, Adaptive::Foundation::SmartDateTime ^result)
{
	bool returnValue = false;

	if ((s == nullptr) || (s == String::Empty))
	{
		if (s == nullptr)
			result = gcnew SmartDateTime(true);
		else
			result = gcnew SmartDateTime(false);
		returnValue=true;
	}
	else
	{
		DateTime% test = *(gcnew DateTime());
		returnValue = DateTime::TryParse(s, test);
		if (returnValue)
			result = gcnew SmartDateTime(test);
		else
			result = nullptr;
	}
	return returnValue;

}
bool SmartDateTime::TryParse(System::String ^s, System::IFormatProvider ^provider, System::Globalization::DateTimeStyles styles, Adaptive::Foundation::SmartDateTime ^result)
{
	bool returnValue = false;

	if ((s == nullptr) || (s == String::Empty))
	{
		if (s == nullptr)
			result = gcnew SmartDateTime(true);
		else
			result = gcnew SmartDateTime(false);
		returnValue=true;
	}
	else
	{
		DateTime% test = *(gcnew DateTime());
		returnValue = DateTime::TryParse(s, provider, styles, test);
		if (returnValue)
			result = gcnew SmartDateTime(test);
		else
			result = nullptr;
	}
	return returnValue;
}
bool SmartDateTime::TryParseExact(System::String ^s, cli::array<System::String ^,1> ^formats, System::IFormatProvider ^provider, System::Globalization::DateTimeStyles style, Adaptive::Foundation::SmartDateTime ^result)
{
	bool returnValue = false;

	if ((s == nullptr) || (s == String::Empty))
	{
		if (s == nullptr)
			result = gcnew SmartDateTime(true);
		else
			result = gcnew SmartDateTime(false);
		returnValue=true;
	}
	else
	{
		DateTime% test = *(gcnew DateTime());
		returnValue = DateTime::TryParseExact(s, formats, provider, style, test);
		if (returnValue)
			result = gcnew SmartDateTime(test);
		else
			result = nullptr;
	}
	return returnValue;
}
bool SmartDateTime::TryParseExact(System::String ^s, System::String ^format, System::IFormatProvider ^provider, System::Globalization::DateTimeStyles style, Adaptive::Foundation::SmartDateTime ^result)
{
	bool returnValue = false;

	if ((s == nullptr) || (s == String::Empty))
	{
		if (s == nullptr)
			result = gcnew SmartDateTime(true);
		else
			result = gcnew SmartDateTime(false);
		returnValue=true;
	}
	else
	{
		DateTime% test = *(gcnew DateTime());
		returnValue = DateTime::TryParseExact(s, format, provider, style, test);
		if (returnValue)
			result = gcnew SmartDateTime(test);
		else
			result = nullptr;
	}
	return returnValue;
}

#pragma endregion

/*--------------------------------------------------------------------------------
 * Private Methods / Functions
 *------------------------------------------------------------------------------*/
#pragma region Private Methods / Functions
int	SmartDateTime::InternalCompare(__int64 leftTicks, __int64 rightTicks)
{
	int returnValue = 0;

    if (leftTicks > rightTicks)
		returnValue = 1;
	else if (leftTicks < rightTicks)
		returnValue = -1;
	return returnValue;     
}
#pragma endregion
